package net.cattaka.allcom.android;

import com.felicanetworks.mfc.AppInfo;
import com.felicanetworks.mfc.Felica;
import com.felicanetworks.mfc.FelicaEventListener;
import com.felicanetworks.mfc.FelicaException;
import com.felicanetworks.mfc.PushIntentSegment;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

/**
 * 受け付け用Activity.
 * FeliCaを使ってINTENTを飛ばす
 * 
 * @author katsuya kato @kacchi0516
 *
 * */

public class ReceptionActivity extends Activity implements Runnable, View.OnClickListener {
	public static final boolean DEBUG_FLG = true;
	public static final String TAG = "ReceptionActivity";

	private final int PUSH_TIMEOUT = 10000;	// Push送信のアプリ側でのタイムアウト時間
    private static final String KEY_CURRENT_ID = "current_id";
	private Button mButtonReception;
	private Button mButtonRest;
	private int mId = 0;
	private ProgressDialog mExecutingPushDialog;


	//** Felicaサービスと接続して、activateが完了した */
	private static final int HANDLE_FELICA_IS_READY = 0x01;

	//** Felicaサービスをinactivateして、サービスとの接続が解除された */
	private static final int HANDLE_FELICA_IS_INACTIVATED = 0x02;

	private final Handler mHandler = new Handler() {
		public void dispatchMessage(android.os.Message msg) {
			switch(msg.what) {
			case HANDLE_FELICA_IS_READY :
				((TextView)findViewById(R.id.state)).setText("Felica Is Ready");
				if(DEBUG_FLG)  Log.d(TAG, "FeliCa Is Ready.");
				break;
			case HANDLE_FELICA_IS_INACTIVATED :
				if(DEBUG_FLG)  Log.d(TAG, "Service unbind");
				break;
			}
		}
	};

	private boolean mConnected = false;
	private Felica mFelica = null;

	/** FeliCaを初期化する際に使用する証明書文字列（nullを指定） */
	private static final String[] CERTS = null;

	/*
	 * FeliCaサービスと接続するのコネクションインターフェース
	 */
	private final ServiceConnection mFelicaConnection = new ServiceConnection() {

		/*
		 * (non-Javadoc)
		 * @see android.content.ServiceConnection#onServiceConnected(android.content.ComponentName, android.os.IBinder)
		 */
		public void onServiceConnected(ComponentName name, IBinder service) {
			if(DEBUG_FLG)  Log.d(TAG, "onServiceConnected");

			// Felicaインスタンスを取得する
			mFelica = ((Felica.LocalBinder) service).getInstance();
			mConnected = true;

			if(mFelica == null) {
				Toast.makeText(getApplicationContext(), "Cannot  obtained a Felica object",  Toast.LENGTH_SHORT).show();

			} else {
				try {
					mFelica.activateFelica(CERTS, mFelicaEventListener);
				} catch (IllegalArgumentException e) {
					Log.e(TAG, "IllegalArgumentException", e);
				} catch (FelicaException e) {
					Toast.makeText(getApplicationContext(), "Felica cannot activate.",  Toast.LENGTH_SHORT).show();
				}
			}
		}

		/*
		 * (non-Javadoc)
		 * @see android.content.ServiceConnection#onServiceDisconnected(android.content.ComponentName)
		 */
		public void onServiceDisconnected(ComponentName name) {
			if(DEBUG_FLG)  Log.d(TAG, "onServiceDisconnected");

			mFelica = null;

			// Felicaの設定解除
			mConnected = false;

			mHandler.sendEmptyMessage(HANDLE_FELICA_IS_INACTIVATED);
		}

	};

	// FeliCaのactivateの状態を受け取るリスナー
	private final FelicaEventListener mFelicaEventListener = new FelicaEventListener() {

		/*
		 * (non-Javadoc)
		 * @see com.felicanetworks.mfc.FelicaEventListener#finished()
		 */
		public void finished() {
			try {
				mFelica.open();
			} catch (FelicaException e) {
				Toast.makeText(getApplicationContext(), "Felica cannot open.",  Toast.LENGTH_SHORT).show();
			}
		}

		/*
		 * (non-Javadoc)
		 * @see com.felicanetworks.mfc.FelicamFelicaEventListenerEventListener#errorOccurred(int, java.lang.String, com.felicanetworks.mfc.AppInfo)
		 */
		public void errorOccurred(int id, String msg, AppInfo otherAppInfo) {

			String result = "Felica#activateFelica() failed\nError:";

			switch (id) {
			case FelicaEventListener.TYPE_USED_BY_OTHER_APP:
				// 他アプリケーションによってFeliCaチップが使用中の場合
				result += "FeliCa Chip is used by other application(PID:" + otherAppInfo.getPid()
				+ ")";
				break;
			case FelicaEventListener.TYPE_NOT_FOUND_ERROR:
				// 利用可能な許可証がみつからなかった場合
				result += "valid permits not found";
				break;
			case FelicaEventListener.TYPE_HTTP_ERROR:
				// 許可証検証中にHTTPエラーが発生した場合
				result += "HTTP error";
				break;
			case FelicaEventListener.TYPE_MFC_VERSION_ERROR:
				// MFCのバージョンアップが必要な場合
				result += "MFC version is too old";
				break;
			case FelicaEventListener.TYPE_UTILITY_VERSION_ERROR:
				// MFCユーティリティのバージョンアップが必要な場合
				result += "MFC utility version is too old";
				break;
			case FelicaEventListener.TYPE_UNKNOWN_ERROR:
				// その他のエラー
				result += "unknown error";
				break;
			default:
				// MFC仕様上、想定外のパス
				result += "nexpected error";
				break;
			}
			if (msg != null) {
				result += "\nerror detail:" + msg;
			}

			if(DEBUG_FLG) Log.e(TAG, result);
			
			mExecutingPushDialog.dismiss();
		}
	};

	/*
	 * (non-Javadoc)
	 * @see android.app.Activity#onCreate(android.os.Bundle)
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.reception);

		mExecutingPushDialog = new ProgressDialog(this);

		mButtonReception = (Button)findViewById(R.id.ButtonReception);
		mButtonRest = (Button)findViewById(R.id.ButtonReset);
		mButtonReception.setOnClickListener(this);
		mButtonRest.setOnClickListener(this);		
	}

	/*
	 * (non-Javadoc)
	 * @see android.app.Activity#onResume()
	 */
	@Override
	protected void onResume() {
		super.onResume();

		connectFelicaService();

		SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
		mId = sp.getInt(KEY_CURRENT_ID, 0);

	}

	/*
	 * (non-Javadoc)
	 * @see android.app.Activity#onPause()
	 */
	@Override
	protected void onPause() {
		super.onPause();

		disconnectFelicaService();
		
		SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
		sp.edit().putInt(KEY_CURRENT_ID, mId).commit();
	}

	/**
	 * 接続
	 */
	private void connectFelicaService() {
		if(DEBUG_FLG)  Log.d(TAG, "connectFelicaService");

		Intent intent = new Intent();
		intent.setClass(getApplicationContext(), Felica.class);
		if (!bindService(intent, mFelicaConnection,
				Context.BIND_AUTO_CREATE)) {

			return;
		}
	}

	/**
	 * 切断
	 */
	private void disconnectFelicaService() {
		if(DEBUG_FLG)  Log.d(TAG, "disconnectFelicaService");
		unbindService(mFelicaConnection);
	} 

	@Override
	public void onClick(View v) {
		if (mButtonReception == v) {
			startDialog();
			Thread thread = new Thread(pushToParticipant);
			thread.start();	
		} else if (mButtonRest == v) {
			if(DEBUG_FLG)  Log.d(TAG, "reset ID");
			mId = 0;
		}
	}

	@Override
	public void run() {
		if (DEBUG_FLG)  Log.d(TAG, "execute push");
		
		try {
			mFelica.activateFelica(null, mFelicaEventListener);
        } catch (FelicaException e) {
        	Log.d(TAG,"FelicaException occurred." + e.getID() + ":" + e.getType());
           return;
        } catch (Exception e){
            Log.d(TAG,"Exception occurred.");
            return;
        }
	}

	private void startDialog() {
		mExecutingPushDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
		mExecutingPushDialog.setMessage("処理中です");
		mExecutingPushDialog.setCancelable(true);
		mExecutingPushDialog.show();
	}	
	
	// 参加者に対してPushして FeliCaをインアクティブにする
	private final Runnable pushToParticipant = new Runnable() {
		public void run() {
        	Log.d(TAG,"pushToParticipant");

			long startTime = SystemClock.uptimeMillis();
			boolean success = false;

			while (SystemClock.uptimeMillis() - startTime < PUSH_TIMEOUT) {
				try {
					ComponentName component = new ComponentName(
							"net.cattaka.allcom.android",
					"net.cattaka.allcom.android.RegistActivity");
					Intent intent = new Intent();
					intent.setComponent(component);
					intent.putExtra("ID", String.valueOf(mId));

					PushIntentSegment pushSegment = new PushIntentSegment(intent);
					mFelica.push(pushSegment);

					success = true;
					break;
				} catch (IllegalArgumentException e) {
					Log.e(TAG, "IllegalArgumentException", e);
				} catch (FelicaException e) {
					Log.e(TAG, "FelicaException" + e.getID() + ":" + e.getType());
				}
			}

			if (success) {
				mId++;
			}
			
			try {
                mFelica.close();
            } catch (Exception e){
            	Log.e(TAG, "close error", e);
            }

            try {
            	mFelica.inactivateFelica();
            } catch (Exception e){
            	Log.e(TAG, "inactivateFelica error", e);
            }
            mExecutingPushDialog.dismiss();
			
		}
	};
}
